Estrarre da un file ZIP

Dopo aver visto il il tip da Voi proposto nel mese di maggio, che mostrava come creare file zip compressi, ho programmato questa classe, che permette di estrarre una serie di file (non solo uno) da un archivio ZIP. Vi allego una piccola applicazione realizzata con interfaccia grafica awt che presenta una possibile implementazione di questa classe.
Tip fornito dal Sig. G.Rota
 
Ecco la classe principale:
 
//Classe unzipFile
class unzipFile {
 
    //Stream file sorgente (zip)
    FileInputStream sorgStream=null;
    //Stream file di destinazione
    FileOutputStream destStream=null;
    //Buffer input
    BufferedInputStream sorgStreamBuff=null;
    //Buffer output
    BufferedOutputStream destStreamBuff=null;
    //Stream per leggere da un file .zip
    ZipInputStream zipIn=null;
    //Zip entry
    ZipEntry zipEntry=null;
    //Array dati
    byte[] data=new byte[2048];
    //Stringa destinazione completa
    String destCompleta=null;

 
//sorg deve essere un percorso del tipo c:\prova.zip; dest deve essere un percorso di tipo c:\unzip\

    public void unzipFromTo(String sorg, String dest) {
 
        //Apertura stream di lettura
        try {
            //Apre stream di lettura
            sorgStream=new FileInputStream(sorg);
            //Apre buffer
            sorgStreamBuff=new BufferedInputStream(sorgStream);
        } catch (IOException e) {
            System.out.println("Errore durante l'apertura degli stream");
        }
 
        //Apertura ZipInputStream
        zipIn=new ZipInputStream(sorgStreamBuff);

        //Catch per posizionamento nell'entry da leggere
        try {
            //Apre entry ed esce dal ciclo se non ce ne sono più
            while((zipEntry=zipIn.getNextEntry())!=null) {
 
                //Creazione del percorso del file in cui estrarre l'entry del file zip
                //concatenando il valore di ritorno di ZipEntry.getName() e la cartella scelta dall'utente
                destCompleta=dest + zipEntry.getName();

                //Apre stream di scrittura
                destStream=new FileOutputStream(destCompleta);
                //Apre buffer
                destStreamBuff=new BufferedOutputStream(destStream);

                //Lettura zip e scrittura file decompresso
                int count;
 
                //Legge 2048 byte dal file zip e controlla EOF
                while((count=zipIn.read(data,0,2048))!=-1) {
                    //Scrive su disco i dati decompressi
                    destStreamBuff.write(data,0,count);
                }
 
                //Chiude entry corrente
                zipIn.closeEntry();
                //Chiude file stream di output
                destStreamBuff.close();
                destStream.close();
            }
 
        } catch(IOException e) {
            System.out.println("Errore estrazione file.");
        }

        try {
        //Chiusura file stram e zip stream
        zipIn.close();
        sorgStreamBuff.close();
        } catch(IOException e) {
            System.out.println("Errore chiusura");
        }
    }
}

Eseguire un comando di sistema in Java

Come eseguire un comando, in java, che abbia un argomento con all'interno uno spazio.
Esempio: 
windows -  type "nome file.txt"
Linux      - cat 'nome file.txt'
 
Sia le virgolette, sia gli apicetti che il carattere speciale \ prima dello spazio, non funzionano con Runtime.exe(), poichè quest'utilma fa uso della StringTokenizer per leggere la stringa di comando.
La risposta a questo quesito è quello di utilizzare "un'altra" Runtime.exe; quella che prende come parametro un vettore di Stringhe. Ad essa bisogna passare la linea di comando già suddivisa in token. Tip fornito dal sig. Addisu Matusala

String [] comando={"cat","nome file.txt"};
Runtime.getRuntime().Exec(comado);

Script in cascata

Se si vuole inserire in una pagina HTML uno Javascript che, per mezzo della funzione "document.write", genera un nuovo documento HTML che richiami dei nuovi script in cascata, ci si imbatte nel problema che il browser interpretando tali istanze annulla l’operazione. Per ovviare a questo problema si deve scomporre la chiamata allo script in cascata suddividendo la parola chiave stessa come mostrato nel tip
Tip fornito dal Sig. L.Bertapelle
 
<script language="javascript">
    document.write("<sc"+"ript LANGUAGE=\"JavaScript\" SRC=\"...\"></sc"+"ript>");
</script>

Un approfondimento del Tip “Pass-by-Value e Pass-By-Reference”

Un tip per evitare comportamenti non desiderati nelle proprie applicazioni, gestendo in modo ottimale il “Pass-by-Value e Pass-By-Reference”; in particolare il passaggio dei dati “By Reference” non funziona come tale nelle applicazioni che utilizzano RMI; per meglio comprendere il problema si consideri un metodo di un’interfaccia come il seguente “cambiaAttributo (MioOggetto mioOggetto). Tip fornito dal Sig. M.Barbaro 

import java.rmi.*;

public interface Libreria extends Remote
{
    public void cambiaAttributo(MioOggetto mioOggetto) throws RemoteException;
    ……
}

…… // fine classe

import java.io.Serializable;

public class MioOggetto implements Serializable
{
   public String nome;

   public MioOggetto(String nome)
   {
      this.nome = nome;
   }

   public void setNome(String nome)
   {
      this.nome = nome;
   }

   public String getNome()
   {
     return this.nome;
   }
}

…… // fine classe

Se un programma cliente in un’ipotetica applicazione client/server come il seguente:

import java.rmi.*;

public class Cliente
{
   public static void main(String args[])
   {
      ......
      try
      {
         MioOggetto mioOggetto = new MioOggetto(“Marco”);
         Libreria libreria = (Libreria) Naming.lookup("rmi://127.0.0.1:1099/istanzalibreria”); // Si suppone un oggetto servente abbia memorizzato nel RMIRegistry un istanza di Libreria con il nome indicato.
         libreria.cambiaAttributo(mioOggetto);
         System.out.println(“Nome : “ + mioOggetto.getNome());        
      } // end try
    catch(Exception e)
    {
    }
}

}

intende utilizzare una classe che implementa l’interfaccia “Libreria” e il relativo metodo “cambiaAttributo (MioOggetto mioOggetto)” desiderando che vengano apportate delle modifiche all’istanza dell’oggetto di tipo MioOggetto passato al metodo, occorre sapere che la comunicazione tramite RMI fa si che l’oggetto servente effettui una copia in locale dell’oggetto ricevuto come parametro del metodo e che ogni modifica effettuata su quell’oggetto ha effetto esclusivamente su quella copia e non sull’istanza di mioOggetto nella classe Cliente. Nel caso in esempio se l’implementazione di cambiaAttributo utilizzata dalla nostra applicazione fosse stata del tipo:

…
public void cambiaAttributo(MioOggetto mioOggetto)
{
   mioOggetto.setNome(“Pippo”);
}
…

al termine dell’esecuzione del programma Cliente l’istruzione System evidenziata avrebbe stampato:

Nome : Marco

Soluzione
Per ovviare quindi a questo tipo di problemi, una soluzione è far si che il metodo dell’interfaccia dell’oggetto remoto che si intende utilizzare restituisca un’istanza dell’oggetto che si intendeva passare per riferimento (e di cui quindi si voleva modificare il valore):

public interface Libreria extends Remote
{
    public MioOggetto cambiaAttributo(MioOggetto mioOggetto) throws RemoteException;
    ……
}

Ecco anche come modificare il programma Cliente:

import java.rmi.*;

public class Cliente
{
   public static void main(String args[])
   {
      ......
      try
      {
         MioOggetto mioOggetto = new MioOggetto(“Marco”);
         Libreria libreria = (Libreria) Naming.lookup("rmi://127.0.0.1:1099/istanzalibreria”);
         mioOggetto = libreria.cambiaAttributo(mioOggetto);
         System.out.println(“Nome : “ + mioOggetto.getNome());        
      } // end try
    catch(Exception e)
    {
    }
}

}

Ed ecco infine come è modificata l’implementazione del metodo “cambiaAttributo(MioOggetto)”:

…
public MioOggetto cambiaAttributo(MioOggetto mioOggetto)
{
   mioOggetto.setNome(“Pippo”);

   return mioOggetto;
}
…

L’esecuzione del programma Cliente modificato stamperà il seguente messaggio come volevasi dimostrare:

Nome : Pippo